/**
 * Copyright (C) 2024-2030 Super BilGen & 超亿时代信息技术股份有限公司.All Rights Reserved.
 */
package cn.com.yang.minio.service;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Model cn.com.yang.minio.service.MinioService
 * @Desc  TODO
 * @author yangyijin
 * @since 2025年10月9日-下午7:55:32
 */

@Service
public class MinioService {

    @Autowired
    private MinioClient minioClient;

    @Value("${yang.minio.bucketName}")
    private String bucketName;

    /**
     * 检查存储桶是否存在，不存在则创建
     */
    public void ensureBucketExists() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (!found) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 1. 新增/上传文件
     * @param file Spring MVC 接收的文件对象
     * @return 文件的唯一标识（可以是对象名，也可以是访问URL）
     */
    public String uploadFile(MultipartFile file) throws Exception {
        // 确保桶存在
        ensureBucketExists();

        // 生成一个唯一的文件名，防止覆盖
        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString() + "-" + originalFilename;

        // 上传文件
        try (InputStream inputStream = file.getInputStream()) {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName) // 对象名（在桶中的唯一标识）
                            .stream(inputStream, file.getSize(), -1) // 文件流、大小、分片大小（-1为默认）
                            .contentType(file.getContentType())
                            .build());
        }

        // 返回文件名，用于后续的下载或删除操作
        return fileName;
    }

    /**
     * 2. 查询/下载文件
     * @param fileName 上传时返回的文件唯一标识
     * @return 文件的字节数据（也可改为返回InputStream用于流式下载）
     */
    public byte[] downloadFile(String fileName) throws Exception {
        try (InputStream stream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .build())) {
            // 使用 Apache Commons IO 或 IOUtils 将输入流转换为字节数组
            return IOUtils.toByteArray(stream);
        }
    }

    /**
     * 生成一个临时的预签名URL用于前端预览/下载（另一种查询方式）
     * @param fileName 上传时返回的文件唯一标识
     * @param expiry 链接过期时间（单位：小时）
     * @return 预签名URL
     */
    public String getPresignedObjectUrl(String fileName, Integer expiry) throws Exception {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(fileName)
                        .expiry(expiry, TimeUnit.HOURS)
                        .build());
    }

    /**
     * 3. 删除文件
     * @param fileName 上传时返回的文件唯一标识
     */
    public void deleteFile(String fileName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .build());
    }
}
